package top.hmtools.mapper.plus.mysql;

import java.util.Set;

import org.apache.ibatis.mapping.MappedStatement;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import tk.mybatis.mapper.entity.EntityColumn;
import tk.mybatis.mapper.mapperhelper.EntityHelper;
import tk.mybatis.mapper.mapperhelper.MapperHelper;
import tk.mybatis.mapper.mapperhelper.MapperTemplate;
import tk.mybatis.mapper.mapperhelper.SqlHelper;

/**
 * 通用mapper扩展方法具体实现
 * <br>查
 * @author HyboJ
 *
 */
public class SelectMapperPlusProvider extends MapperTemplate {
	
	private final Logger logger = LoggerFactory.getLogger(SelectMapperPlusProvider.class);

	public SelectMapperPlusProvider(Class<?> mapperClass, MapperHelper mapperHelper) {
		super(mapperClass, mapperHelper);
	}
	
	
	
	
	
	

	

	

	/**
		 * 根据id集合（该表仅有一个主键，最好主键字段名为“id”）获取指定的数据集合，入参为空，会返回所有数据
		 * <br>为能够结合pagehelper分页插件使用，本方法输出的SQL语句不含“limit”
		 * @param ms
		 * @return
		 */
		public String getSomeByIds(MappedStatement ms){
			final Class<?> entityClass = getEntityClass(ms);
	        //修改返回值类型为实体类型
	        setResultType(ms, entityClass);
	        
	        String sql = this.getSomeByIdsStr(entityClass);
	        
	        if(this.logger.isDebugEnabled()){
	        	this.logger.debug(Thread.currentThread().getStackTrace()[1].getMethodName()+"  :  "+sql.toString());
	        }
	        return sql.toString();
		}

	/**
	 * 根据id集合（该表仅有一个主键，最好主键字段名为“id”）获取指定的数据总数，入参为空，会返回所有数据
	 * @param ms
	 * @return
	 */
	public String getCountByIds (MappedStatement ms){
		String sql = this.getSomeByIdsStr(this.getEntityClass(ms));
		int indexOfFrom = sql.toUpperCase().indexOf("FROM");
		sql = "select count(0)  "+sql.substring(indexOfFrom);
		if(this.logger.isDebugEnabled()){
			this.logger.debug(Thread.currentThread().getStackTrace()[1].getMethodName()+"  :  "+sql.toString());
		}
		return sql.toString(); 
	}
	
	/**
	 * 根据id集合（该表仅有一个主键，最好主键字段名为“id”）获取指定的数据集合，入参为空，会返回所有数据  SQL
	 * @param entityClass
	 * @return
	 */
	private String getSomeByIdsStr(Class<?> entityClass){
		//组装查询mybatis sql 脚本模板
        StringBuilder sql = new StringBuilder();
        sql.append(SqlHelper.selectAllColumns(entityClass));
        sql.append(SqlHelper.fromTable(entityClass, tableName(entityClass)));
        sql.append("<where>");
        //获取所有该表的主键
        Set<EntityColumn> pkColumns = EntityHelper.getPKColumns(entityClass);
        for(EntityColumn pkColumn:pkColumns){
        	String ids = "ids";
        	StringBuffer sbSqlPart = new StringBuffer();
        	sbSqlPart.append("<if test=\"null != {{ids}} and {{ids}}.length >0 \">");
        	sbSqlPart.append(pkColumn.getColumn()+" in ");
        	sbSqlPart.append("(");
        	sbSqlPart.append("<foreach collection=\"{{ids}}\" item=\"id\"  index=\"index\" open=\"\" separator=\",\" close=\"\">");
        	
        	sbSqlPart.append("<if test = \"id != null ");
        	if(pkColumn.getJavaType().equals(String.class)){
        		sbSqlPart.append(" and id != ''");
        	}
        	sbSqlPart.append("\" >");
        	sbSqlPart.append("#{id}");
        	sbSqlPart.append("</if>");
        	
        	sbSqlPart.append("</foreach>");
        	sbSqlPart.append(")");
        	sbSqlPart.append("</if>");
        	
        	sql.append(sbSqlPart.toString().replaceAll("\\{\\{ids\\}\\}", ids));
        	
        	//仅取一个即第一个主键，故要求操作的表仅有一个主键
        	break;
        }
        sql.append("</where>");
        sql.append(SqlHelper.orderByDefault(entityClass));
        
        //判断所有主键入参是否有值，全无，则不返回数据  TODO 查询或许不需要使用 limit 0，如果使用，结合 pagehelper 可能会有异常
//        sql.append("<if test=\"");
//        int index = 0;
//        for(EntityColumn pkColumn:pkColumns){
//        	String ids = pkColumn.getProperty()+"s";
//        	StringBuffer sbSqlPart = new StringBuffer();
//        	sbSqlPart.append("({{ids}} == null or {{ids}}.length &lt; 1 )");
//        	index++;
//        	if(index<pkColumns.size()){
//        		sbSqlPart.append(" and ");
//        	}
//        	sql.append(sbSqlPart.toString().replaceAll("\\{\\{ids\\}\\}", ids));
//        }
//        sql.append("\">");
//        sql.append("limit 0");
//        sql.append("</if>");
        return sql.toString();
	}

	/**
	 * 指定主键名称（Java类字段名字符串），主键集合，获取指定记录集合
	 * @param ms
	 * @return
	 */
	public String getSomeByPk(MappedStatement ms){
		final Class<?> entityClass = getEntityClass(ms);
        //修改返回值类型为实体类型
        setResultType(ms, entityClass);
        
        String sql = this.getSomeByPkStr(entityClass);
      		
        if(this.logger.isDebugEnabled()){
        	this.logger.debug(Thread.currentThread().getStackTrace()[1].getMethodName()+"  :  "+sql.toString());
        }
        return sql.toString();
	}
	
	/**
	 * 指定主键名称（Java类字段名字符串），主键集合，获取指定记录总数。入参为空，会返回所有数据
	 * @param ms
	 * @return
	 */
	public String getCountByPk (MappedStatement ms){
		String sql = this.getSomeByPkStr(getEntityClass(ms));
		int indexOfFrom = sql.toUpperCase().indexOf("FROM");
		sql = "select count(0)  "+sql.substring(indexOfFrom);
		if(this.logger.isDebugEnabled()){
			this.logger.debug(Thread.currentThread().getStackTrace()[1].getMethodName()+"  :  "+sql.toString());
		}
		return sql.toString(); 
	}

	/**
	 * 指定主键名称（Java类字段名字符串），主键集合，获取指定记录集合 SQL
	 * @param entityClass
	 * @return
	 */
	private String getSomeByPkStr(Class<?> entityClass){
		//组装查询mybatis sql 脚本模板
        StringBuilder sql = new StringBuilder();
        sql.append(SqlHelper.selectAllColumns(entityClass));
        sql.append(SqlHelper.fromTable(entityClass, tableName(entityClass)));
        sql.append("<where>");
        
      //获取所有该表的主键
        Set<EntityColumn> pkColumns = EntityHelper.getPKColumns(entityClass);
        for(EntityColumn column:pkColumns){
        	StringBuffer sqlPart = new StringBuffer();
        	sqlPart.append("<if test=\" key == '{{key}}' and (ids != null and ids.length > 0) \">");
        	sqlPart.append(" AND "+column.getColumn()+"  IN  ");
        	sqlPart.append("(");
        	sqlPart.append("<foreach collection=\"ids\" item=\"id\"  index=\"index\" open=\"\" separator=\",\" close=\"\">");
        	
        	sqlPart.append("<if test = \"id != null ");
        	if(column.getJavaType().equals(String.class)){
        		sqlPart.append(" and id != ''");
        	}
        	sqlPart.append("\" >");
        	
        	sqlPart.append("#{id}");
        	sqlPart.append("</if>");
        	sqlPart.append("</foreach>");
        	sqlPart.append(")");
        	sqlPart.append("</if>");
        	sql.append(sqlPart.toString().replaceAll("\\{\\{key\\}\\}", column.getProperty()));
        }
        
        sql.append("</where>");
        sql.append(SqlHelper.orderByDefault(entityClass));
        
//      //入参为空的处理 TODO 查询或许不需要使用 limit 0，如果使用，结合 pagehelper 可能会有异常
//      		sql.append("<if test=\" key == null or key == '' or ids == null or (ids != null and ids.length &lt; 1) \">");
//      		sql.append("limit 0");
//      		sql.append("</if>");
        
        return sql.toString();
	}
	
	/**
	 * 根据条件获取对应数据
	 * <br>为能够结合pagehelper分页插件使用，本方法输出的SQL语句不含“limit”
	 * @param ms
	 * @return
	 */
	public String getSomeByCondition (MappedStatement ms){
		Class<?> entityClass = getEntityClass(ms);
        //修改返回值类型为实体类型
        setResultType(ms, entityClass);
        
        String sql = this.getSomeByConditionStr(entityClass);
        
        if(this.logger.isDebugEnabled()){
        	this.logger.debug(Thread.currentThread().getStackTrace()[1].getMethodName()+"  :  "+sql.toString());
		}
		return sql.toString();
	}
	
	/**
	 * 根据条件获取对应数据总数
	 * @param ms
	 * @return
	 */
	public String getCountByCondition (MappedStatement ms){
		String sql = this.getSomeByConditionStr(getEntityClass(ms));
		int indexOfFrom = sql.toUpperCase().indexOf("FROM");
		sql = "select count(0)  "+sql.substring(indexOfFrom);
		if(this.logger.isDebugEnabled()){
			this.logger.debug(Thread.currentThread().getStackTrace()[1].getMethodName()+"  :  "+sql.toString());
		}
		return sql.toString(); 
	}

	/**
	 * 根据条件获取对应数据 的 SQL 语句
	 * @param entityClass
	 * @return
	 */
	private String getSomeByConditionStr(Class<?> entityClass){
		StringBuilder sql = new StringBuilder();
        sql.append(SqlHelper.selectAllColumns(entityClass));
        sql.append(SqlHelper.fromTable(entityClass, tableName(entityClass)));
        sql.append(SqlHelper.whereAllIfColumns(entityClass, isNotEmpty()));
        sql.append(SqlHelper.orderByDefault(entityClass));
        return sql.toString();
	}
	
	/**
	 * 根据指定的主键名称、主键集合，获取数据库中存在的主键集合数据
	 * <br>为能够结合pagehelper分页插件使用，本方法输出的SQL语句不含“limit”
	 * @param ms
	 * @return
	 */
	public String getExistPksByPk (MappedStatement ms){
		Class<?> entityClass = getEntityClass(ms);
		//获取所有该表的主键
		Set<EntityColumn> pkColumns = EntityHelper.getPKColumns(entityClass);
		
		StringBuilder sql = new StringBuilder();
		sql.append("SELECT ");
		
		//获取与入参“key”同值的主键属性名称
		for(EntityColumn column:pkColumns){
			sql.append("<if test=\"  ");
			sql.append(" key == '" +column.getProperty()+ "'");
			sql.append("  \">");
			sql.append("  "+column.getColumn()+"  ");
			sql.append("</if>");
		}
		
		sql.append(SqlHelper.fromTable(entityClass, tableName(entityClass)));
		
		//条件
		sql.append(" <where> ");
		
		for(EntityColumn column:pkColumns){
        	StringBuffer sqlPart = new StringBuffer();
        	sqlPart.append("<if test=\" key == '{{key}}' and (ids != null and ids.length > 0) \">");
        	sqlPart.append("  "+column.getColumn()+"  IN  ");
        	sqlPart.append("(");
        	sqlPart.append("<foreach collection=\"ids\" item=\"id\"  index=\"index\" open=\"\" separator=\",\" close=\"\">");
        	
        	sqlPart.append("<if test = \"id != null ");
        	if(column.getJavaType().equals(String.class)){
        		sqlPart.append(" and id != ''");
        	}
        	sqlPart.append("\" >");
        	
        	sqlPart.append("#{id}");
        	sqlPart.append("</if>");
        	sqlPart.append("</foreach>");
        	sqlPart.append(")");
        	sqlPart.append("</if>");
        	sql.append(sqlPart.toString().replaceAll("\\{\\{key\\}\\}", column.getProperty()));
        }
		
		sql.append(" </where> ");
		
		
		if(this.logger.isDebugEnabled()){
			this.logger.debug(Thread.currentThread().getStackTrace()[1].getMethodName()+"  :  "+sql.toString());
		}
		return sql.toString();
	}
	
	/**
	 * 根据指定的主键名称、主键集合，获取数据库中存在的主键集合数据总数
	 * @param ms
	 * @return
	 */
	public String getExistPksCountByPk (MappedStatement ms){
		String sql = this.getExistPksByPk(ms);
		int indexOfFrom = sql.toUpperCase().indexOf("FROM");
		sql = "select count(0)  "+sql.substring(indexOfFrom);
		if(this.logger.isDebugEnabled()){
			this.logger.debug(Thread.currentThread().getStackTrace()[1].getMethodName()+"  :  "+sql.toString());
		}
		return sql.toString(); 
	}
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
}
